////////////////////////////////////////////////////////////////////////////////////////////////////
//																			                      //
//  Filename:    TreasureChamberGuts.cpp				                    					  //
//  Developer:   Ben Wardlow												                      //
//  Create date: 7/10/2006													                      //
//																			                      //
////////////////////////////////////////////////////////////////////////////////////////////////////
//																								  //
//  Description: This is the class implementation for the slot gut of the Australian Slot machine //
//				 called Treasure Chamber.														  //
//																			                      //
////////////////////////////////////////////////////////////////////////////////////////////////////
//        		Copyright (c) 2006 - Realtime Gaming.  All rights reserved.		                  //
////////////////////////////////////////////////////////////////////////////////////////////////////

#include "TreasureChamberGuts.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
/// TreasureChamberGuts::m_aLineWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of icons.  It is indexed by
/// wheel icon and then count.  So to get the SpinResult for 5 Jaguars, use the following code
/// snippet:
///
///		SpinResult result = m_aLineWinSpinResults[ ICON_JAGUAR ][ 5 ];
///
/// In this example result would be set to EVT_FIVE_JAGUAR.
////////////////////////////////////////////////////////////////////////////////////////////////////
TreasureChamberGuts::SpinResult TreasureChamberGuts::m_aLineWinSpinResults[][ 6 ] =
{
// Number of icons:		0			1			2				3					4					5
/* ICON_NINE */		{	EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_NINE,		EVT_FOUR_NINE,		EVT_FIVE_NINE	},
/* ICON_TEN */		{	EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_TEN,		EVT_FOUR_TEN,		EVT_FIVE_TEN	},
/* ICON_JACK */		{	EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_JACK,		EVT_FOUR_JACK,		EVT_FIVE_JACK	},
/* ICON_QUEEN */	{	EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_QUEEN,	EVT_FOUR_QUEEN,		EVT_FIVE_QUEEN	},
/* ICON_KING */		{	EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_KING,		EVT_FOUR_KING,		EVT_FIVE_KING	},
/* ICON_ACE */		{	EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_ACE,		EVT_FOUR_ACE,		EVT_FIVE_ACE	},
/* ICON_FALCON */	{	EVT_LOSER,	EVT_LOSER,	EVT_TWO_FALCON,	EVT_THREE_FALCON,	EVT_FOUR_FALCON,	EVT_FIVE_FALCON	},
/* ICON_JAGUAR */	{	EVT_LOSER,	EVT_LOSER,	EVT_TWO_JAGUAR,	EVT_THREE_JAGUAR,	EVT_FOUR_JAGUAR,	EVT_FIVE_JAGUAR	},
/* ICON_WOMAN */	{	EVT_LOSER,	EVT_LOSER,	EVT_TWO_WOMAN,	EVT_THREE_WOMAN,	EVT_FOUR_WOMAN,		EVT_FIVE_WOMAN	},
/* ICON_QUESTION */	{	EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_LOSER,			EVT_LOSER		},
/* ICON_ROSE */		{	EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_LOSER,			EVT_LOSER		},
/* ICON_MAN */		{	EVT_LOSER,	EVT_LOSER,	EVT_TWO_MAN,	EVT_THREE_MAN,		EVT_FOUR_MAN,		EVT_FIVE_MAN	},
};

////////////////////////////////////////////////////////////////////////////////////////////////////
/// TreasureChamberGuts::m_aScatterWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of icons.  It is indexed by icon
/// count only, since Rose is the only scatter win.  So to get the SpinResult for 3 Roses, use the
/// following code snippet:
///
///		SpinResult result = m_aScatterWinSpinResults[ 3 ];
///
/// In this example result would be set to EVT_THREE_ROSE.
////////////////////////////////////////////////////////////////////////////////////////////////////
TreasureChamberGuts::SpinResult TreasureChamberGuts::m_aScatterWinSpinResults[ 6 ] =
{
	// ICON_ROSE		   Number of Icons
	EVT_LOSER,				// 0
	EVT_SCATTER_NEAR_MISS,	// 1
	EVT_SCATTER_NEAR_MISS,	// 2
	EVT_THREE_ROSE,			// 3
	EVT_FOUR_ROSE,			// 4
	EVT_FIVE_ROSE			// 5
};

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::TreasureChamberGuts()
///
/// This is the default constructor for the class.
////////////////////////////////////////////////////////////////////////////////////////////////////
TreasureChamberGuts::TreasureChamberGuts()
{
	// If this doesn't compile it means that someone probably added
	// another icon type but did not update the m_aLineWinSpinResults array.
	C_ASSERT( countof( m_aLineWinSpinResults ) == NUM_VALID_ICONS );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::~TreasureChamberGuts()
///
/// This is the destructor for the class.
////////////////////////////////////////////////////////////////////////////////////////////////////
TreasureChamberGuts::~TreasureChamberGuts()
{
	deallocateSubstitutionIcons();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::load( Info* info )
///
/// @brief	Override of the SlotGuts::load framework function.
///			Allocates our map of substitution icons.
///
/// @return	bool8
///
/// @param	info
////////////////////////////////////////////////////////////////////////////////////////////////////
bool8
TreasureChamberGuts::load( Info *info )
{
	// Load the base class, and the substitution icons.
	return super::load( info ) && allocateSubstitutionIcons();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::allocateSubGameData()
///
/// @brief	Override of the SlotGuts::allocateSubGameData framework function.
///			Overridden to initialize the icon substitution positions.
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::allocateSubGameData()
{
	super::allocateSubGameData();

	// Reset to initialize...
	resetSubstitutions();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::allocateSubstitutionIcons()
///
/// @brief  Examines each SlotReel, and makes icons that can be passed from the override getIcon()
///			method when the Question Mark has revealed another icon.
///
///         NOTE - this implementation assumes that the base class won't destroy the wheelhouse
///			once it's been loaded!
///
/// @return bool8 - flag indicating that the substitution icons were allocated
////////////////////////////////////////////////////////////////////////////////////////////////////
bool8
TreasureChamberGuts::allocateSubstitutionIcons()
{
	const SlotReel* pReel = NULL;

	// Go through each reel and make copies of the icons that could get substituted.
	for( uint8 reel = 0 ; reel < getReelCount() ; ++reel )
	{
		pReel = getSlotReel( MODE_NORMAL, reel );

		for( SlotReel::const_iterator begin( pReel->begin() ), current( pReel->begin() ), end( pReel->end() );
				current != end;
				++current )
		{
			if ( (*current)->iconid == ICON_QUESTION )
			{
				addSubstitutionIcon( *current );
			}
		}

		// also for the free games
		pReel = getSlotReel( MODE_FREE_SPIN, reel );

		for( SlotReel::const_iterator begin( pReel->begin() ), current( pReel->begin() ), end( pReel->end() );
				current != end;
				++current )
		{
			if ( (*current)->iconid == ICON_QUESTION )
			{
				addSubstitutionIcon( *current );
			}
		}
	}

	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::deallocateSubstitutionIcons()
///
/// @brief	Clean up our icons substitution map
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::deallocateSubstitutionIcons()
{
	// Clean up our substitution map
	for( SlotIconSubstitutionMap::iterator current( m_mapSubstitutionIcons.begin() ),
		end( m_mapSubstitutionIcons.end() );
			current != end;
			++current )
	{
		delete current->second;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::addSubstitutionIcon( const SlotIcon* icon )
///
/// @brief	Adds an icon duplicating the passed icon for use in the getIcon() method during free
///			games.
///
/// @param	const SlotIcon* icon - the icon to copy and key against in the new mapping.
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::addSubstitutionIcon( const SlotIcon* icon )
{
	// Map this icon to a substitution icon
	// Copy the supplied icon
	SlotIcon* subicon = new SlotIcon( *icon );

	// Map it back to the real iterator for later.
	VERIFY( m_mapSubstitutionIcons.insert( make_pair( icon, subicon ) ).second );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::resetSubstitutions()
///
/// This function resets all of the icon substitutions in preparation for a new spin.
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::resetSubstitutions()
{
	// Just set the sub-game data back to 0.
    m_subGame->update( SGDIDX_REEL_SUBST_1, 0 );
    m_subGame->update( SGDIDX_REEL_SUBST_2, 0 );
    m_subGame->update( SGDIDX_REEL_SUBST_3, 0 );
    m_subGame->update( SGDIDX_REEL_SUBST_4, 0 );
    m_subGame->update( SGDIDX_REEL_SUBST_5, 0 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::preSpinClassifyResults( SlotSpin* spin )
///
/// @param	spin - Pointer to the spin with stop data.
///
/// This method is overridden to alter the reel stops for the substitutions..
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::preSpinClassifyResults( SlotSpin* spin )
{
	super::preSpinClassifyResults(spin);

	// Assume that we have no Question Marks.
    resetSubstitutions();
    m_nQuestionMarkScatter = 0;

    // Loop through all of the reels.
    for ( uint8 reel = 0; reel < getReelCount(); reel++ )
    {
		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		for ( uint8 row = 0 ; row < 3 ; ++row )
        {
        	// Get the current stop.
            uint8 stop = relativeWheelPosition( getGameModeId(), reel, spin->getStops()[ reel ], row );

            const SlotIcon* pIcon = getIcon( getGameModeId(), reel, stop );

            // If this is a Question Mark...
            if ( pIcon->iconid == ICON_QUESTION )
            {
            	// Figure out what we are going to replace it with.
            	int32 nNewIconId;
				
				if ( getGameModeId() == MODE_NORMAL )
				{
					// use the regular probability table
					nNewIconId = getRandomValueFromProbabilityTable( PT_QUESTION_MARK_REVEAL );
				}
				else
				{
					// use the free games probability table
					nNewIconId = getRandomValueFromProbabilityTable( PT_QUESTION_MARK_REVEAL_FREE_GAMES );
				}

				if ( m_bDebugSpinsMode )
				{
					if ( g_nDebugQuestionMarks[ reel ] > 0 )
					{
						nNewIconId = g_nDebugQuestionMarks[ reel ];
						g_nDebugQuestionMarks[ reel ] = -1;
					}
				}

				setSubstitution( reel, pIcon, nNewIconId );

				// and set the bit in the position mask for this stop.
				m_nQuestionMarkScatter |= 1 << position;

                break;
            }

			// Move to the next bit in the position mask.
            position += 5;
        }
    }

	//reset debug data
	if(m_bDebugSpinsMode)
		g_nDebugQuestionMarkIndex = -1;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::setSubstitution( uint8 nReel, const SlotIcon* pOldIcon,
///				int32 nNewIcon)
///
/// @param	nReel      - the reel on which the substitution takes place
/// @param	pOldIcon   - the original icon
/// @param	nNewIconId - the id of the new icon
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::setSubstitution( uint8 nReel, const SlotIcon* pOldIcon, int32 nNewIconId )
{
	// Simple bounds check.
	ASSERT( nReel < getReelCount() );

	// Update the sub-game data.
    m_subGame->update( SGDIDX_REEL_SUBST_1 + nReel, nNewIconId );

	SlotIconSubstitutionMap::iterator substitute = m_mapSubstitutionIcons.find( pOldIcon );

	if( substitute != m_mapSubstitutionIcons.end() )
	{
		substitute->second->iconid = nNewIconId;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::getSubstitution( uint8 nReel )
///
/// Accessor function to get the stop position to substitute.
///
/// @param	nReel - the reel on which the substitution takes place
///
/// @return int32
////////////////////////////////////////////////////////////////////////////////////////////////////
int32
TreasureChamberGuts::getSubstitution( uint8 nReel ) const
{
	// Simple bounds check.
	ASSERT( nReel < getReelCount() );

	// Just return the sub-game data for the reel.
    return m_subGame->getData( SGDIDX_REEL_SUBST_1 + nReel );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamber::getIcon( uint8 gamemodeID, uint8 reelID, uint8 position )
///
/// @brief	Returns the SlotIcon for the specified gamemode, reel and position.
///         If the icon is a Question Mark, and the substitution has already been
///         made, then the icon returned is the substitution.
///
/// @return const SlotIcon*  - the icon at the position of the reel after possible substitution
///
/// @param 	gamemodeID - the game mode id
/// @param 	reelID     - the reel for which we want to find the icon
/// @param 	position   - the reel position for which we want to find the icon
////////////////////////////////////////////////////////////////////////////////////////////////////
const
SlotIcon* TreasureChamberGuts::getIcon( uint8 gamemodeID, uint8 reelID, uint8 position ) const
{
	const SlotIcon* pRealIcon = super::getIcon( gamemodeID, reelID, position );

	// If this is a Question Mark and we have already made the substitution, then
	// return the substitution.
    if ( pRealIcon->iconid == ICON_QUESTION &&  getSubstitution( reelID ) )
    {
		SlotIconSubstitutionMap::const_iterator substitute = m_mapSubstitutionIcons.find( pRealIcon );

		// If this is a stop that has been substituted, return the duplicate icon.
		if( substitute != m_mapSubstitutionIcons.end() )
		{
			return substitute->second;
		}
	}

	return pRealIcon;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::SpinResult TreasureChamberGuts::getManLineWinResult( uint8* stops ) const
///
/// @param  stops - The array of stop positions for the line.
///
/// @return	SpinResult - a payout from the SpinResult enumeration.
///
/// This helper method is used to calculate the Man line win payout.
////////////////////////////////////////////////////////////////////////////////////////////////////
TreasureChamberGuts::SpinResult
TreasureChamberGuts::getManLineWinResult( uint8* stops ) const
{
	// Count how many Man icons we have at the beginning of the line.
	for ( uint8 i = 0; i < getReelCount(); i++ )
    {
		// If this icon is not a Man...
		if ( getIcon( getGameModeId(), i, stops[i] )->iconid != ICON_MAN )
		{
			// then we have our total.
			break;
		}
    }

	// Use the array to look up the spin result for i Man icons.
	return lookupLineWinSpinResult( ICON_MAN, i );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::doesManLineWinPayMore( SpinResult srMan, SpinResult srOther ) const
///
/// @param  srMan   - The spin result to calculate the Man payout for.
/// @param  srOther - The spin result to calculate the other payout for.
///
/// @return	bool - True if the Man win is larger.
///
/// This helper method is used to see which payout is larger.
////////////////////////////////////////////////////////////////////////////////////////////////////
bool
TreasureChamberGuts::doesManLineWinPayMore( SpinResult srMan, SpinResult srOther ) const
{
	// If the Man line win is five Man, then no substitution took place
	// and we want to use the line win.
	if ( srMan == EVT_FIVE_MAN )
	{
		return true;
	}

	// Lookup the payout for the Man line win.
	long nManLineWinPayout = getPayout( srMan )->payoutAmount;

	// See what the total payout for the other line win is without the substitution
	// multiplier (if any).
	long nOtherLineWinPayout = getPayout( srOther )->payoutAmount;

	// Return true if the Man payout is bigger.
    return ( nManLineWinPayout > nOtherLineWinPayout );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::classifyStops( SpinLine* spinline, uint8* stops, uint8 bet,
///				uint8 line, uint8& rtnresult, uint8& multiplier )
///
/// @param	spinline   -
/// @param  stops      - The array of stop positions for the line.
/// @param  bet        - The value of the line bet.
/// @param  line       - The index of the line.
/// @param	rtnresult  -
/// @param  multiplier -
///
/// This helper method is used to calculate the payout on a line.
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::classifyStops( SpinLine* spinline, uint8* stops, uint8 bet, uint8 line,
	uint8& rtnresult, uint8& multiplier )
{
	// Track the Man result separately since it might be changed to a substitution.
	SpinResult srManLineWinResult = getManLineWinResult( stops );

	// Declare a local variable to track whether or not we found a substitution.
	bool bSubstitution = false;

	// Also keep track of the number of relevant icons for a line win
	uint8 nNumIcons = 0;

	// Now see what the payout is if we use any Man icons we find as substitution symbols.
	// Start with the icon on the first reel, since all symbols pay left to right.
	uint8 testIcon = getIcon( getGameModeId(), 0, stops[ 0 ] )->iconid;

	// See what the spin result is if we used any Man icons as substitution symbols.
	SpinResult srResultWithPossibleSubstitution =
		getLineWinResultWithPossibleSubstitution( stops, testIcon, bSubstitution, nNumIcons );

	// Use the larger payout between the regular Man evaluation compared to
	// the evaluation with the possible Man substitution.
    if ( doesManLineWinPayMore( srManLineWinResult, srResultWithPossibleSubstitution ) )
	{
		// The Man icons by themselves pay out more so use the Man result.
		rtnresult = srManLineWinResult;
	}
	else
	{
		// Otherwise the result with the substitution (if any) paid more so use it.
		rtnresult = srResultWithPossibleSubstitution;

		// If we did actually have a substitution and a winning spin...
		if ( bSubstitution && srResultWithPossibleSubstitution != EVT_LOSER )
		{
			// then add a note.
			spinline->addNote( NOTE_SUBSTITUTION );
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::getLineWinResultWithPossibleSubstitution( uint8* stops,
///				uint8 testIcon, bool& bSubstitution ) const
///
/// @param	stops		  - The array of stop positions for the line.
/// @param  testIcon	  - The icon we are looking for, typically the first icon on the line.
/// @param  bSubstitution - An output parameter that is set if a subsitution is used.
///
/// @return	SpinResult - a payout from the SpinResult enumeration.
///
/// This helper method is used to calculate the line win payout with a possible substitution.
////////////////////////////////////////////////////////////////////////////////////////////////////
TreasureChamberGuts::SpinResult
TreasureChamberGuts::getLineWinResultWithPossibleSubstitution( uint8* stops, uint8 testIcon,
	bool& bSubstitution, uint8& numLineWinIcons ) const
{
	// Initialize the out parameter
	bSubstitution = false;

	// Loop through the remaining reels until the streak is over
	for ( int i = 1; i < getReelCount(); i++ )
    {
		// See what this icon is.
		uint8 currentIcon = getIcon( getGameModeId(), i, stops[i] )->iconid;

		// If the current icon is a Man...
		if ( currentIcon == ICON_MAN )
		{
			// then use it as a substitution symbol and continue on.
			bSubstitution = true;
			continue;
		}
		// Otherwise if the test icon is a Man...
		else if ( testIcon == ICON_MAN )
		{
			// then we still have a substitution.  In this case the line
			// started out with a Man.
			bSubstitution = true;

			// We have now found our first icon that is not a Man.  All
			// of the rest of the icons will have to match this one now for the
			// streak to continue, so change our test icon.
			testIcon = currentIcon;
			continue;
		}

		// If the current icon is not the test icon...
        if ( currentIcon != testIcon )
        {
			// then the streak is over so break out of the loop
			break;
        }
    }

	// Pass this information back to the calling function so we can determine how many
	// Man icons, if any, contributed to the line win
	numLineWinIcons = i;

	// Use the array to look up the spin result for i testIcons.
	return lookupLineWinSpinResult( testIcon, i );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::classifyScatters( SlotSpin* spin )
///
/// @param  spin - Pointer to the spin with stop data.
///
/// This is an override of the framework method. It determines if the current spin merits free spins
/// or scatter payments.
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::classifyScatters( SlotSpin* spin )
{
	// Try for the Random Progressive Jackpot
	tryForJackpot( spin );

	// Declare a local variable to track the scatter positions.
	int32 nScatterPositions = 0;

	// See if there is a scatter.
	SpinResult srResult = getScatterWinResult( spin, nScatterPositions );

	// Add the scatter, if any.
	evaluateScatterWin( spin, srResult, nScatterPositions );

	// See if we triggered the free game feature.
	evaluateFeatureTrigger( spin, srResult, nScatterPositions );

	// If we found any Question Marks...
	if ( m_nQuestionMarkScatter )
	{
		// let the client know about them.
		spin->addScatter( m_nQuestionMarkScatter, 0, 0, false, EVT_LOSER, 0 );
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::getScatterWinResult( SlotSpin* spin, int32& scatterPositions )
///
/// @param  spin			 - The spin we are evaluating.
/// @param  scatterPositions - An output parameter that contains a bit mask for the icon positions.
///
/// @return	SpinResult - a payout from the SpinResult enumeration.
///
///	This function looks for scatter wins.
////////////////////////////////////////////////////////////////////////////////////////////////////
TreasureChamberGuts::SpinResult
TreasureChamberGuts::getScatterWinResult( SlotSpin* spin, int32& scatterPositions ) const
{
	// Declare a local variable to keep up with the icon count.
	uint8 numScatterIcons = 0;

	// Initialize the scatterPositions.
	scatterPositions = 0;

	// Loop through each reel.
  	for( int reel = 0; reel < getReelCount(); reel++ )
	{
		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Loop through each row in the wheel house.
		for( int row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel, spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;

			// If the icon is the one we are looking for...
			if ( currentIcon == ICON_ROSE )
			{
				// then increase the icon count
				numScatterIcons++;

				// Set the bit in the position mask for this stop.
				scatterPositions |= 1 << position;
			}

			// Move to the next bit in the position mask.
            position += 5;
		}
	}

	return lookupScatterWinSpinResult( numScatterIcons );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::evaluateScatterWin( SlotSpin* spin,
///				SpinResult srScatterResult, int32 scatterpositions )
///
/// This function determines if the current spin wins a scatter payment and adds the scatter.
///
/// @param	spin
/// @param	srScatterResult
/// @param	scatterpositions
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::evaluateScatterWin( SlotSpin* spin, SpinResult srScatterResult, int32 scatterPositions )
{
	// If we got the scatter win (or almost got it)
	if ( srScatterResult != EVT_LOSER )
	{
		// Get the base payout for the scatter.
		int32 nPayout = getPayout( srScatterResult )->payoutAmount;

		// Scatters payout based on the total bet, so factor in the number of bet lines.
		nPayout *= spin->getSpinLineCount();

		// Default to no multiplier.
		int32 nMultiplier = 1;

		// Free Spin mode has a multiplier.
		if( getGameModeId() == MODE_FREE_SPIN )
		{
			nMultiplier = MULTIPLIER_FREE_SPIN;
		}

		// Add the payout to the total win for this spin.
		increaseTotalWin( nPayout * nMultiplier );

		// Add a scatter to the spin.
		//SlotScatter* pScatter =
		spin->addScatter( scatterPositions, nPayout * getBetPerLine(), nMultiplier, false, srScatterResult, 0 );
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::evaluateFeatureTrigger( SlotSpin* spin,
///				SpinResult srScatterResult, int32 featurePositions )
///
/// This function determines if the current spin triggers the free game feature and adds the scatter.
///
/// @param	spin
/// @param	srScatterResult
/// @param	featurePositions
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::evaluateFeatureTrigger( SlotSpin* spin, SpinResult srScatterResult,
	int32 featurePositions )
{
	// Keep up with the number of icons we have and their location.
	uint8 nNumRose = 0;
	int32 nRoseScatter = 0;

	// We need a spin result for the feature trigger.
	SpinResult srFeatureTrigger = EVT_LOSER;

	nNumRose = getNumFeatureTriggerIcons( spin, ICON_ROSE, nRoseScatter );

	// If we found any Roses...
	if ( nNumRose )
	{
		int32 nFreeSpins = 0;

		// Three or more Roses will trigger the free game feature.
		if ( nNumRose >= 3 )
		{
			// We have a winner.
			srFeatureTrigger = EVT_FREE_GAMES;

			// Change the game mode.
			setGameModeId( MODE_FREE_SPIN );

			// Add the free spins.
			nFreeSpins = 20;
			incrementFreeSpins( nFreeSpins );
		}
		else
		{
			// Anything less is a near miss.
			srFeatureTrigger = EVT_SCATTER_NEAR_MISS;
		}

		// Add the scatter to the spin.
		spin->addScatter( nRoseScatter, 0, 0, false, srFeatureTrigger, nFreeSpins );
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::getNumFeatureTriggerIcons( SlotSpin* spin, uint8 icon,
///				int32& scatterPositions )
///
/// @param	spin				The current spin object.
/// @param  icon				The icon to search for.
/// @param  scatterPositions	The bit mask for the scatter positions that we find.
///
/// @return	uint8
///
/// This helper method is used to evaluate the spin for scatters.
////////////////////////////////////////////////////////////////////////////////////////////////////
uint8
TreasureChamberGuts::getNumFeatureTriggerIcons( SlotSpin* spin, uint8 icon, int32& scatterPositions ) const
{
	// Declare a local variable to keep up with the icon count.
	uint8 numFeatureTriggerIcons = 0;

	// Initialize the scatterPositions.
	scatterPositions = 0;

	// Loop through each reel.
  	for( uint8 reel = 0; reel < getReelCount(); reel++ )
	{
		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Loop through each row in the wheel house.
		for( uint8 row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel,
					spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;

			// If the icon is the one we are looking for...
			if ( currentIcon == icon )
			{
				// then increase the icon count
				numFeatureTriggerIcons++;

				// and set the bit in the position mask for this stop.
				scatterPositions |= 1 << position;
			}

			// Move to the next bit in the position mask.
   			position += 5;
		}
	}

	return numFeatureTriggerIcons;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::tryForJackpot( SlotSpin* spin )
///
///	This function tries to win the jackpot and adds the scatter if we hit the jackpot.
///
/// @param	spin
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::tryForJackpot( SlotSpin* spin )
{
	// If we are in the first paid spin (NOT a bonus spin)...
	if ( getGameModeId() == MODE_NORMAL )
	{
		// then try for the Random Progressive Jackpot
		// If we hit the jackpot...
		if ( getRandomProgressiveJackpotResult( spin->getSpinLineCount() )
             || m_bForceRandomJackpot == true )
		{
			// then add a jackpot scatter to the spin.
			spin->addScatter( 0, getPayout( EVT_RANDOM_PROGRESSIVE_WINNER )->payoutAmount, 1,
				true, EVT_RANDOM_PROGRESSIVE_WINNER, 0 );
		}
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	TreasureChamberGuts::isValidGuts()
///
/// @return	bool8 - true if gut is valid.
///
/// This helper method is used to see if the current gut ID is valid.
////////////////////////////////////////////////////////////////////////////////////////////////////
bool8
TreasureChamberGuts::isValidGuts()
{
	return getGutsId() >= MIN && getGutsId() < MAX ;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn		TreasureChamberGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier,
///				uint8& nNoteId )
///
/// @param  nGameModeMultiplier	The multiplier for the game mode.
/// @param  nNoteId				The note ID for the game mode.
///
/// This helper method is used to get the game mode multiplier and note ID.
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier, uint8& nNoteId )
{
	// If we are in free spin mode...
    if ( getGameModeId() == MODE_FREE_SPIN )
    {
		// then return the free spin multiplier...
        nGameModeMultiplier = MULTIPLIER_FREE_SPIN;

		// and the free spin note.
        nNoteId = NOTE_FREE_SPIN_3X;
    }
    else
    {
		// just defer to the base class.
        SlotGuts::getGameModeMultiplierAndNoteId( nGameModeMultiplier, nNoteId );
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Debug spins functionality, can control what the question mark icons reveal
////////////////////////////////////////////////////////////////////////////////////////////////////
void
TreasureChamberGuts::initDebugFunctionMap()
{
	SlotGuts::initDebugFunctionMap();

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_FALCON,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionFalcon) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_JAGUAR,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionJaguar) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_WOMAN,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionWoman) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_ROSE,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionRose) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_MAN,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionMan) );



	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_REEL_1,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionReel1) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_REEL_2,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionReel2) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_REEL_3,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionReel3) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_REEL_4,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionReel4) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_QUESTION_REEL_5,
		new DebugStopFunc<TreasureChamberGuts>(this, &TreasureChamberGuts::DebugFeature_QuestionReel5) );
}

int TreasureChamberGuts::g_nDebugQuestionMarkIndex = -1;
int TreasureChamberGuts::g_nDebugQuestionMarks[5] = { -1 };


void TreasureChamberGuts::DebugFeature_QuestionFalcon(SlotSpin *spin )
{
	if(g_nDebugQuestionMarkIndex >= 0)
	{
		g_nDebugQuestionMarks[g_nDebugQuestionMarkIndex] = ICON_FALCON;
	}
}
void TreasureChamberGuts::DebugFeature_QuestionJaguar(SlotSpin *spin )
{
	if(g_nDebugQuestionMarkIndex >= 0)
	{
		g_nDebugQuestionMarks[g_nDebugQuestionMarkIndex] = ICON_JAGUAR;
	}
}
void TreasureChamberGuts::DebugFeature_QuestionWoman(SlotSpin *spin )
{
	if(g_nDebugQuestionMarkIndex >= 0)
	{
		g_nDebugQuestionMarks[g_nDebugQuestionMarkIndex] = ICON_WOMAN;
	}
}
void TreasureChamberGuts::DebugFeature_QuestionRose(SlotSpin *spin )
{
	if(g_nDebugQuestionMarkIndex >= 0)
	{
		g_nDebugQuestionMarks[g_nDebugQuestionMarkIndex] = ICON_ROSE;
	}
}
void TreasureChamberGuts::DebugFeature_QuestionMan(SlotSpin *spin )
{
	if(g_nDebugQuestionMarkIndex >= 0)
	{
		g_nDebugQuestionMarks[g_nDebugQuestionMarkIndex] = ICON_MAN;
	}
}
void TreasureChamberGuts::DebugFeature_QuestionReel1( SlotSpin *spin )
{
	g_nDebugQuestionMarkIndex = 0;
}
void TreasureChamberGuts::DebugFeature_QuestionReel2( SlotSpin *spin )
{
	g_nDebugQuestionMarkIndex = 1;
}
void TreasureChamberGuts::DebugFeature_QuestionReel3( SlotSpin *spin )
{
	g_nDebugQuestionMarkIndex = 2;
}
void TreasureChamberGuts::DebugFeature_QuestionReel4( SlotSpin *spin )
{
	g_nDebugQuestionMarkIndex = 3;
}
void TreasureChamberGuts::DebugFeature_QuestionReel5( SlotSpin *spin )
{
	g_nDebugQuestionMarkIndex = 4;
}
